package org.example;

import lombok.Getter;
import org.example.annotation.MyRpc;
import org.example.loadBalancers.LoadBalanceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URI;



//实现InvocationHandler  内部不需要持有原类
public class RpcInvocationHandler implements InvocationHandler {


    @Getter
    //这个是固定的 就是接口名首字母小写 是rpc代理类的名字
    private final String beanName;


    @Autowired
    private  LoadBalanceContext loadBalanceContext;

    @Autowired
    private  RestTemplate restTemplate;


    public RpcInvocationHandler(String beanName) {
        this.beanName = beanName;

    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        //这里不需要实现类 因为之前是实现类原方法增强  现在我自己从0实现方法
        //获取a的地址 这里所有方法都是统一的
        String remoteUrl = loadBalanceContext.getServiceInstance(beanName).getUrl();

        //1. 获得 注解中的路径和请求方法
        MyRpc myRpc = method.getAnnotation(MyRpc.class);
        String path = myRpc.path();
        String methodType = myRpc.method();

        //拿到参数的名 与参数的值args对应
        Parameter[] parameters = method.getParameters();


        // 2.调用远程相关方法
        return executeRemoteMethod(methodType, path, args, remoteUrl,parameters);

    }


    //TODO 暂时没有路径参数的参数  后续再说
    //调用远程方法 根据不同的参数发送请求
    private Object executeRemoteMethod(String methodType, String path, Object[] args, String remoteUrl, Parameter[] parameters) {

        //2.调用a的相关方法
        switch (methodType) {
            case "GET":

                return executeGetMethod(path, args, remoteUrl,  parameters);

            case "POST":
                return restTemplate.postForObject(remoteUrl + path, args, String.class);
            default:
                throw new RuntimeException("不支持的请求方法");
        }
    }


    //处理get请求 get理论上不能有请求体  所以只有路径参数
    private Object executeGetMethod(String path, Object[] args, String remoteUrl, Parameter[] parameters) {


        URI uri = buildUri(remoteUrl, path, args, parameters);

        return restTemplate.getForObject(uri, String.class);

    }


    //TODO  传json请求体和混合传待定
    private Object executePostMethod(String path, Object[] args, String remoteUrl, Parameter[] parameters) {

        //如果是请求参数 则与get一样
        URI uri = buildUri(remoteUrl, path, args, parameters);

        return restTemplate.postForObject(uri,null, String.class);

    }



    //构造请求参数加路径的uri
    private URI buildUri(String remoteUrl, String path,Object[] args, Parameter[] parameters) {

        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(remoteUrl+path);
        //构建参数
        for (int i = 0; i < parameters.length; i++) {
            uriBuilder.queryParam(parameters[i].getName(), args[i]);
        }

        return uriBuilder.build().encode().toUri();
    }



}